﻿using Basic.Oss.Interfaces;
using Basic.Oss.Options;
using Microsoft.Extensions.Options;
using Shared.Const.Enum.Oss;

namespace Basic.Oss.Implements;

/// <summary>
/// 阿里云OSS服务
/// </summary>
public sealed class AliYunOssService : IOssService
{
    private readonly AliOssOptions _options;
    private readonly OssClient _ossClient;

    private string DefaultRoot { get; set; }

    public AliYunOssService(IOptions<FileStorageOption> options)
    {
        DefaultRoot = OssConstData.DefaultBucketName;
        _options = options.Value.AliOssConfig;
        if (_options == null)
        {
            throw new ArgumentNullException(nameof(FileStorageOption.AliOssConfig));
        }
        _ossClient = new OssClient(_options.Endpoint, _options.AccessKeyId, _options.AccessKeySecret);
    }

    private string GetOssFileName(string ossFileName, EnumOssDir dir = EnumOssDir.RootDir)
    {
        return dir == EnumOssDir.RootDir ? ossFileName : $"{dir.GetEnumItem().TextName}/{ossFileName}";
    }

    public bool DeleteFile(string ossFileName)
    {
        ossFileName = GetOssFileName(ossFileName, EnumOssDir.FileDir);
        var res = _ossClient.DeleteObject(DefaultRoot, ossFileName);
        return res != null && res.HttpStatusCode == System.Net.HttpStatusCode.NoContent;
    }

    public Task<bool> DeleteFileAsync(string ossFileName)
    {
        ossFileName = GetOssFileName(ossFileName, EnumOssDir.FileDir);
        var res = _ossClient.DeleteObject(DefaultRoot, ossFileName);
        return Task.FromResult(res != null && res.HttpStatusCode == System.Net.HttpStatusCode.NoContent);
    }

    public byte[] GetFileBytes(string ossFileName)
    {
        ossFileName = GetOssFileName(ossFileName, EnumOssDir.FileDir);
        var obj = _ossClient.GetObject(DefaultRoot, ossFileName);
        if (obj == null || obj.Content == null || obj.Content.Length == 0)
            return new byte[0];

        using Stream stream = obj.Content;
        using MemoryStream ms = new MemoryStream();
        stream.CopyTo(ms);
        if (ms.CanSeek) ms.Seek(0, SeekOrigin.Begin);
        return ms.ToArray();
    }

    public async Task<byte[]> GetFileBytesAsync(string ossFileName)
    {
        ossFileName = GetOssFileName(ossFileName, EnumOssDir.FileDir);
        var obj = _ossClient.GetObject(DefaultRoot, ossFileName);
        if (obj == null || obj.Content == null || obj.Content.Length == 0)
            return new byte[0];

        using Stream stream = obj.Content;
        using MemoryStream ms = new MemoryStream();
        await stream.CopyToAsync(ms);
        if (ms.CanSeek) ms.Seek(0, SeekOrigin.Begin);
        return ms.ToArray();
    }

    public Stream GetFileStream(string ossFileName)
    {
        var url = GetOssFileName(ossFileName, EnumOssDir.FileDir);
        var obj = _ossClient.GetObject(DefaultRoot, url);
        return (obj == null || obj.Content == null || obj.Content.Length == 0) ? Stream.Null : obj.Content;
    }

    public Task<Stream> GetFileStreamAsync(string ossFileName)
    {
        var fileUrl = GetOssFileName(ossFileName, EnumOssDir.FileDir);
        var obj = _ossClient.GetObject(DefaultRoot, fileUrl);
        Stream stream = (obj == null || obj.Content == null || obj.Content.Length == 0) ? Stream.Null : obj.Content;
        return Task.FromResult(stream);
    }

    public string GetFileUrl(string ossFileName)
    {
        var fileUrl = GetOssFileName(ossFileName, EnumOssDir.FileDir);
        var request = new GeneratePresignedUriRequest(DefaultRoot, fileUrl, SignHttpMethod.Get);
        //设置过期时间
        request.Expiration = DateTime.Now.AddYears(99);
        var signedUrl = _ossClient.GeneratePresignedUri(request);
        return signedUrl.ToString();
    }

    public bool PutFile(Stream stream, string ossFileName)
    {
        ossFileName = GetOssFileName(ossFileName, EnumOssDir.FileDir);
        if (stream.CanSeek)
            stream.Seek(0, SeekOrigin.Begin);
        using PutObjectResult result = _ossClient.PutObject(DefaultRoot, ossFileName, stream);
        return result.HttpStatusCode == System.Net.HttpStatusCode.OK;
    }

    public bool PutFile(byte[] bytes, string ossFileName)
    {
        ossFileName = GetOssFileName(ossFileName, EnumOssDir.FileDir);
        using MemoryStream ms = new MemoryStream(bytes);
        using PutObjectResult result = _ossClient.PutObject(DefaultRoot, ossFileName, ms);
        return result.HttpStatusCode == System.Net.HttpStatusCode.OK;
    }

    public Task<bool> PutFileAsync(Stream stream, string ossFileName)
    {
        bool rs = PutFile(stream, ossFileName);
        return Task.FromResult(rs);
    }

    public Task<bool> PutFileAsync(byte[] bytes, string ossFileName)
    {
        bool rs = PutFile(bytes, ossFileName);
        return Task.FromResult(rs);
    }

}